home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Tools / MPW / lgrind 1.0.1 / lgrind.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-04-24  |  40.1 KB  |  1,477 lines  |  [TEXT/MPS ]

  1. /* lgrind.c, a %%\LaTeX%% version of tgrind, which is a %%\TeX%% version
  2.  * of vgrind.  Used to `grind nice program listings'.
  3.  */
  4.  
  5. #ifndef lint
  6. static char sccsid[] = "@(#)@(#)tfontedpr.c    1.3 (LBL) 4/12/85";
  7. static char Version[] =
  8.    "$Id: lgrind.c,v 1.4 91/10/01 00:36:11 gvr Exp $";
  9. #endif
  10.    
  11. /* lgrind --- general purpose "pretty printer" for use with %%\LaTeX%%.
  12.  *
  13.  * Copyright %%\copyright%% 1985 by Van Jacobson, Lawrence Berkeley Laboratory
  14.  * This program may be freely used and copied but may not be sold
  15.  * without the author's written permission.  This notice must remain
  16.  * in any copy or derivative.
  17.  *
  18.  * This program is an adaptation of "vfontedpr" v4.2 (12/11/84) from
  19.  * the 4.2bsd Unix distribution.  Vfontedpr was written by Dave
  20.  * Presotto (based on an earlier program of the same name written by
  21.  * Bill Joy).
  22.  *
  23.  * I would welcome comments, enhancements, bug fixes, etc.  Please 
  24.  * mail them to:
  25.  *    van@@lbl-rtsg.arpa    (from arpanet, milnet, csnet, etc.)
  26.  *    ..!ucbvax!lbl-csam!van    (from Usenet/UUCP)
  27.  *
  28.  * Modifications.
  29.  * --------------
  30.  * 30 Mar 85    Chris & Van    Fixed %|\C|% & %|\S|% (comment & string start
  31.  *                indicators to really appear at the start of
  32.  *                comments & strings.  Changes for speeded-up
  33.  *                @expmatch()@.
  34.  * 29 Mar 85    Chris Torek    (chris@@maryland):  Bug fixes for %|~|% and
  35.  *                %|^L|% output.  Most cpu-time eaters recoded
  36.  *                to improve efficiency.
  37.  * 10 Feb 85    Van        Written.
  38.  *  8 Oct 87    JSL        Modified so as to compile on VMS.  On VMS, we
  39.  *                don't use a surrounding shell script, so the
  40.  *                options are a bit different --- added %|-i|% to
  41.  *                make a file to be %|\input|% in a %%\LaTeX%%
  42.  *                environment.  Changed some of the characters
  43.  *                around --- e.g., we always take %|*|% in math
  44.  *                mode (to make it centered) so we have to
  45.  *                write %|*|% as %|\*|%.  Etc.
  46.  * 14 Jan 88    JSL        %|-e|% option for embedded code.
  47.  * 22 Jan 88    JSL        Bugfix --- program could overrun @pstack@
  48.  *                because of an incorrect limit test.
  49.  *    Sep 91    George V Reilly    Reformated and cleaned up code, including
  50.  *                naughtiness with @NULL@.  Added %|@|%,
  51.  *                %|%%|%, %|%$|%, and %%\tt \%|%% features.
  52.  *                Also the %|%<|%, %|%!|%, and %|%#|% features.
  53.  * 24 Apr 93    Fred Walsteijn    Ported to Apple Macintosh MPW Shell: @#ifdef MPW@
  54.  *                we must disable Unix @popen()@ and @pclose()@, and
  55.  *                use %|"}}\n"|% instead of %|"\\^M"|% in @printtab@.
  56.  *                Fixed bug in %|printf("\\rhead[...|% too.
  57.  */
  58.    
  59. #include <stdio.h>
  60. #include <ctype.h>
  61.  
  62. #ifdef MPW
  63. #  define popen(command,type) NULL
  64. #  define pclose(stream)      (-1)
  65. #endif
  66.  
  67. #ifndef vms
  68. #  include <sys/types.h>
  69. #  include <sys/stat.h>
  70. #  include <time.h>
  71. #else
  72. #  include <types.h>
  73. #  include <stat.h>
  74. #endif
  75.    
  76. typedef    int boolean;
  77.  
  78. #define TRUE  1
  79. #define FALSE 0
  80.  
  81. #define STANDARD 0
  82. #define ALTERNATE 1
  83.    
  84. #define    NOTCODE 0        /* the three states of @incode@ */
  85. #define INITCODE 1
  86. #define OTHERCODE 2
  87.  
  88. #define PNAMELEN 80        /* length of a function/procedure name */
  89. #define PSMAX 20        /* size of procedure name stacking */
  90.    
  91. #define    BUFFERSIZE    4096
  92.  
  93. #ifndef vms
  94. #  define OKEXIT    0
  95. #  define BADEXIT    1
  96. #  ifndef DEFSFILE
  97. #    define DEFSFILE    "/usr/lib/lgrindefs"
  98. #  endif
  99. #else
  100. #  define OKEXIT    1
  101. #  define BADEXIT    0
  102. #  define DEFSFILE    "TEX$INPUTS:lgrindefs.src"
  103. #endif
  104.    
  105.  
  106. /* regular expression routines */
  107.    
  108. char    *expmatch();        /* match a string to an expression */
  109. char    *convexp();        /* convert expression to internal form */
  110.  
  111.  
  112. /* database query routines */
  113.  
  114. char    *tgetstr();
  115. int     tgetent();
  116. int     tgetflag();
  117.  
  118.  
  119. /* forward declarations */
  120.  
  121. void    setlang();
  122. void    readfile();
  123. void    putScp();
  124. void    putKcp();
  125. void    putVcp();
  126. void    putstr();
  127. boolean    isproc();
  128. void    outchar();
  129.  
  130.  
  131. /*
  132.  *    The state variables
  133.  */
  134.  
  135. boolean    incomm;            /* in a comment of the primary type */
  136. boolean    instr;            /* in a string constant */
  137. boolean    inchr;            /* in a character constant */
  138. int    incode;            /* in program text within a comment */
  139. int    latexcode;        /* in program text within %%\LaTeX%% */
  140. int    latex_tt;        /* in %|\tt|% text within %%\LaTeX%% */
  141. boolean    use_tt;            /* use %|\tt|% everywhere */
  142. boolean    do_at;            /* pay attention to %|@|%s in %%\LaTeX%% */
  143. boolean    do_tt;            /* pay attention to %|||%s in %%\LaTeX%% */
  144. boolean    nokeyw = FALSE;        /* no keywords being flagged */
  145. boolean    prccont;        /* continue last procedure */
  146. boolean    code_cmnts = TRUE;    /* Treat %|@|%, etc specially in comments */
  147. boolean    code_latex = TRUE;    /* Treat %|@|%, etc specially in %%\LaTeX%% */
  148. boolean    linehead;        /* at beginning of line or after whitespace */
  149. int    lastout;        /* (extended) last character to outchar */
  150. int    comtype;        /* type of comment */
  151. int    psptr;            /* the stack index of the current procedure */
  152. char    pstack[PSMAX][PNAMELEN+1]; /* the procedure name stack */
  153. int    plstack[PSMAX];        /* the procedure nesting level stack */
  154. int    blklevel;        /* current nesting level */
  155. char    *fname = "";        /* File being read */
  156. int    lineno;            /* Line number in that file */
  157. char    pname[BUFFERSIZE+1];    /* Current procedure name */
  158.  
  159.  
  160. /*
  161.  *    The language specific globals
  162.  */
  163.  
  164. char    *defsfile = DEFSFILE;    /* name of language definitions file */
  165. char    language[PNAMELEN]="c";    /* the language indicator */
  166. char    the_buf[BUFFERSIZE+1];    /* general purpose buffer */
  167. char    *buf = the_buf + 1;    /* @buf-1@ must be valid */
  168. char    strings[2*BUFFERSIZE];    /* store the keywords */
  169. char    defs[2 * BUFFERSIZE];    /* language definitions from lgrindefs */
  170. char    *l_keywds[BUFFERSIZE/2];/* keyword table address */
  171. char    *l_prcbeg;        /* regular expr for procedure begin */
  172. char    *l_combeg;        /* regexp introducing a comment */
  173. char    *l_comend;        /* regexp ending a comment */
  174. char    *l_acmbeg;        /* regexp introducing a comment */
  175. char    *l_acmend;        /* regexp ending a comment */
  176. char    *l_blkbeg;        /* regexp beginning of a block */
  177. char    *l_blkend;        /* regexp ending a block */
  178. char    *l_strbeg;        /* regexp starting string constant */
  179. char    *l_strend;        /* regexp ending string constant */
  180. char    *l_chrbeg;        /* regexp starting character constant */
  181. char    *l_chrend;        /* regexp ending character constant */
  182. char    *l_cdebeg;        /* regexp starting prog text within comment */
  183. char     s_cdebeg[PNAMELEN+1];    /* actual string corresponding to @l_cdebeg@ */
  184. char    *l_cdeend;        /* regexp ending prog text within comment */
  185. char    *l_texbeg;        /* regexp starting %%\TeX%% text in comment */
  186. char    *l_texend;        /* regexp ending %%\TeX%% text in comment */
  187. char    *l_txmbeg;        /* regexp starting %%\TeX%% math in comment */
  188. char    *l_txmend;        /* regexp ending %%\TeX%% math in comment */
  189. char    *l_tt_beg;        /* regexp starting verbatim text in comment */
  190. char    *l_tt_end;        /* regexp ending typewriter text in comment */
  191. char    *l_at;            /* regexp for %|@|% in %%\LaTeX%% text */
  192. char    *l_tt;            /* regexp for %|||% in %%\LaTeX%% text */
  193. char    *l_pc;            /* regexp for %|%|% in %%\LaTeX%% text */
  194. char    l_escape;        /* character used to escape characters */
  195. boolean    l_toplex;        /* procedures only defined at top lex level */
  196. boolean    l_onecase;        /* upper & lower case equivalent */
  197. boolean    embed = FALSE;        /* -e seen --- do embedded code */
  198. boolean    code = TRUE;        /* Looking at code */
  199.  
  200.  
  201. /*
  202.  *  global variables also used by expmatch
  203.  */
  204.  
  205. extern    boolean    _escaped;    /* if last character was an escape */
  206. extern    char *_start;        /* start of the current string */
  207.  
  208.  
  209. extern    int (*re_strncmp)();    /* function to do string compares */
  210. extern    int strncmp();
  211. extern    int lc_strncmp();
  212.  
  213.  
  214.  
  215.    int
  216. main(argc, argv)
  217.    int    argc;
  218.    char    *argv[];
  219. {
  220.    struct stat    stbuf;
  221.    char        *p;
  222.    boolean    hseen = FALSE;        /* -h seen        */
  223.    char        *hstring;        /* header string to use    */
  224.    boolean    iseen = FALSE;        /* -i seen        */
  225.    int        files_done = 0;
  226.    
  227.    argc = getredirection(argc, argv);
  228.    
  229.    argc--, argv++;
  230.    do {
  231.       register char *cp;
  232.       register int i;
  233.       
  234.       if (argc > 0) {
  235.      if (!strcmp(argv[0], "-h")) {
  236.         hseen = TRUE;
  237.         if (argc == 1) {
  238.            hstring = "";
  239.            argc = 0;
  240.            goto rest;
  241.         }
  242.         hstring = argv[1];
  243.         argc--, argv++;
  244.         argc--, argv++;
  245.         if (argc > 0)
  246.            continue;
  247.         goto rest;
  248.      }
  249.      
  250.      /* take input from the standard place */
  251.      if (!strcmp(argv[0], "-")) {
  252.         argc = 0;
  253.         goto rest;
  254.      }
  255.      
  256.      /* Process embedded text */
  257.      if (!strcmp(argv[0], "-e")) {
  258.         embed = TRUE;
  259.         argc--, argv++;
  260.         continue;
  261.      }
  262.  
  263.      /* format for inclusion */
  264.      if (!strcmp(argv[0], "-i")) {
  265.         iseen = TRUE;
  266.         argc--, argv++;
  267.         continue;
  268.      }
  269.  
  270.      /* indicate no keywords */
  271.      if (!strcmp(argv[0], "-n")) {
  272.         nokeyw++;
  273.         argc--, argv++;
  274.         continue;
  275.      }
  276.      
  277.      /* Don't treat %|@|%, etc. specially in comments */
  278.      if (!strcmp(argv[0], "-c")) {
  279.         code_cmnts = FALSE;
  280.         argc--, argv++;
  281.         continue;
  282.      }
  283.      
  284.      /* Do treat %|@|%, etc. specially in comments */
  285.      if (!strcmp(argv[0], "+c")) {
  286.         code_cmnts = TRUE;
  287.         argc--, argv++;
  288.         continue;
  289.      }
  290.      
  291.      /* Don't treat %|@|%, etc. specially in
  292.       * %%\LaTeX%% text (@embed@ only) */
  293.      if (!strcmp(argv[0], "-a")) {
  294.         code_latex = FALSE;
  295.         argc--, argv++;
  296.         continue;
  297.      }
  298.      
  299.      /* Do treat %|@|%, etc. specially in
  300.       * %%\LaTeX%% text (@embed@ only) */
  301.      if (!strcmp(argv[0], "+a")) {
  302.         code_latex = TRUE;
  303.         argc--, argv++;
  304.         continue;
  305.      }
  306.      
  307.      /* Use %|\tt|% for all fonts */
  308.      if (!strcmp(argv[0], "-t")) {
  309.         use_tt = TRUE;
  310.         argc--, argv++;
  311.         continue;
  312.      }
  313.      
  314.      /* specify the language */
  315.      if (!strncmp(argv[0], "-l", 2)) {
  316.         strcpy(language, argv[0]+2);
  317.         argc--, argv++;
  318.         continue;
  319.      }
  320.      
  321.      /* specify the language description file */
  322.      if (!strncmp(argv[0], "-d", 2)) {
  323.         defsfile = argv[1];
  324.         argc--, argv++;
  325.         argc--, argv++;
  326.         continue;
  327.      }
  328.      
  329.      /* open the file for input */
  330.      if (freopen(argv[0], "r", stdin) == NULL) {
  331.         perror(argv[0]);
  332.         exit(BADEXIT);
  333.      }
  334.      
  335.      fname = argv[0];
  336.      lineno = 0;
  337.      argc--, argv++;
  338.       }
  339.    rest:
  340.       
  341.       if (iseen && embed) {
  342.      fprintf(stderr, "-i makes no sense with -e; -e ignored\n");
  343.      embed = FALSE;
  344.       }
  345.  
  346.       if (!iseen && !embed) {
  347.      if (files_done == 0) {
  348.         printf("\\documentstyle[lgrind,fancyhead]{article}\n");
  349.         printf("\\pagestyle{fancy}\n");
  350.      }
  351.      printf("\\lhead[\\fancyplain{}{\\bf\\thepage}]");
  352.      printf("{\\fancyplain{}{\\bf %s}}\n",
  353.         fname);
  354.      printf("\\rhead[\\fancyplain{}{\\bf %s}]",
  355.         fname);
  356.          printf("{\\fancyplain{}{\\bf\\thepage}}\n");
  357.      printf("\\cfoot{}\n");
  358.      if (files_done == 0) {
  359.         printf("\\begin{document}\n");
  360.      }
  361.      printf("\\begin{lgrind}\n");
  362.       }
  363.       
  364.       if (embed)
  365.      printf("%% This document was generated automagically by lgrind.  DO NOT EDIT.\n\n");
  366.       if (iseen)
  367.      printf("%% Remember to use the lgrind style\n\n");
  368.       
  369.       if (hseen) {
  370.      printf("\\Head{");
  371.      putstr(hstring);
  372.      printf("}\n");
  373.       }
  374.  
  375.       setlang();
  376.  
  377.       /* initialize the program */
  378.       
  379.       incomm = instr = inchr = _escaped = FALSE;
  380.       incode = latexcode = latex_tt = NOTCODE;
  381.       do_at = do_tt = TRUE;
  382.       blklevel = 0;
  383.       for (psptr = 0; psptr < PSMAX; psptr++) {
  384.      pstack[psptr][0] = '\0';
  385.      plstack[psptr] = 0;
  386.       }
  387.       psptr = -1;
  388.       fstat(fileno(stdin), &stbuf);
  389.       cp = ctime(&stbuf.st_mtime);
  390.       cp[10] = cp[16] = cp[24] = '\0';
  391.  
  392.       if (!embed) {
  393.      printf("\\File{");
  394.      putstr(fname);
  395.      printf("},{%s},{%s %s}\n", cp+11, cp+4, cp+20);
  396.       }
  397.       
  398.       code = FALSE;
  399.       readfile(stdin);
  400.       files_done++;
  401.  
  402.       if (!iseen && !embed) {
  403.      printf("\\end{lgrind}\n");
  404.       }
  405.  
  406.       if (code)
  407.      fprintf(stderr, "Reached EOF within code in file %s\n", fname);
  408.    } while (argc > 0);
  409.    
  410.    if (!iseen && !embed) {
  411.       printf("\\end{document}\n");
  412.    }
  413.    exit(OKEXIT);
  414. }
  415.  
  416.  
  417.  
  418. /*
  419.  * @readfile()@ --- read and process a file
  420.  */
  421.    void
  422. readfile(fp)
  423.    FILE *fp;
  424. {
  425.    register char *cp;
  426.    boolean    inline = FALSE;    /* Doing %( -- %)    */
  427.    char        term;        /* ']' or ')'        */
  428.    char        *atptr;        /* start of %|@|% within %%\LaTeX%% text */
  429.    char        *atendptr;    /* end of %|@|% within %%\LaTeX%% text */
  430.    char        *ttptr;        /* start of %|||% within %%\LaTeX%% text */
  431.    char        *ttendptr;    /* end of %|||% within %%\LaTeX%% text */
  432.    char        *pcptr;        /* start of %|%|% within %%\LaTeX%% text */
  433.    char        *pcendptr;    /* end of %|%|% within %%\LaTeX%% text */
  434.    char        temp[BUFFERSIZE];
  435.  
  436.    while (fgets(buf, BUFFERSIZE, fp) != NULL) {
  437.       lineno++;
  438.       cp = buf;
  439.       linehead = TRUE;
  440.       lastout = '\0';
  441.       if (embed) {
  442.      if (!code) {
  443.         if (buf[0] == '%' &&
  444.         (buf[1] == '[' || buf[1] == '('
  445.          || buf[1] == '#' || buf[1] == '<' || buf[1] == '!'
  446.          || buf[1] == '@' || buf[1] == '|')) {
  447.            
  448.            for (cp = buf + 2; *cp == ' ' || *cp == '\t'; cp++)
  449.           ;
  450.  
  451.            /* Change the language */
  452.            if (buf[1] == '#') {
  453.           if (*cp == '\n')
  454.              fprintf(stderr, "no language seen after %%#\n");
  455.           else {
  456.              cp[strlen(cp) - 1] = '\0';    /* nuke the @'\n'@ */
  457.              strcpy(language, cp);
  458.              printf("%% switching to %s\n", language);
  459.              setlang();
  460.           }
  461.           continue;
  462.            }
  463.            
  464.            /* Turn %|@|% or %|||% processing within %%\LaTeX%%
  465.             * text on or off. */
  466.  
  467.            if (buf[1] == '@' || buf[1] == '|') {
  468.           if (*cp == '\n')
  469.              fprintf(stderr, "no setting seen after %%%c\n", buf[1]);
  470.           else {
  471.              int flag = (*cp == '1' || *cp == '+');
  472.              if (buf[1] == '@')
  473.             do_at = flag;
  474.              else
  475.             do_tt = flag;
  476.           }
  477.           continue;
  478.            }
  479.            
  480.            code = TRUE;
  481.            
  482.            /* take input from another file or from a shell command */
  483.            if (buf[1] == '<' || buf[1] == '!') {
  484.           FILE *fp;
  485.           char source = buf[1];
  486.  
  487.           cp[strlen(cp) - 1] = '\0';    /* nuke the @'\n'@ */
  488.           if (source == '<')
  489.              fp = fopen(cp, "r");
  490.           else /* @source == '!'@ */
  491.              fp = popen(cp, "r");
  492.  
  493.           if (fp == NULL) {
  494.              sprintf(temp, "%%%c on `%s' failed", source, cp);
  495.              perror(temp);
  496.           } else {
  497.              strcpy(temp, cp);
  498.              printf("%% start of `%s'\n", temp);
  499.              /* printf("\\LGinlinefalse\\LGbegin\\lgrinde\n"); */
  500.              printf("\\begin{lgrind}\n");
  501.              readfile(fp);
  502.              /* printf("\\endlgrinde\\LGend\n"); */
  503.              printf("\\end{lgrind}\n");
  504.              printf("%% end of `%s'\n", temp);
  505.              if (source == '<')
  506.             fclose(fp);
  507.              else
  508.             pclose(fp);
  509.           }
  510.           code = FALSE;
  511.           continue;
  512.            }
  513.            
  514.            /* embedded inline or displayed code */
  515.            if (buf[1] == '(') {
  516.           inline = TRUE;
  517.           term = ')';
  518.           printf("\\LGinlinetrue");
  519.            } else {    /* @buf[1] == '['@ */
  520.           inline = FALSE;
  521.           term = ']';
  522.           printf("\\LGinlinefalse");
  523.            }
  524.            if (buf[2] == '\n') {
  525.           printf("\\LGbegin\\lgrinde\n");
  526.            } else {
  527.           buf[strlen(buf)-1] = '\0';
  528.           printf("%s\\lgrinde\n", &buf[2]);
  529.            }
  530.            continue;
  531.  
  532.         } else if (do_at &&
  533.                (atendptr = expmatch(buf, l_at, &atptr,
  534.                         (char *) NULL)) != NULL) {
  535.            /* This is a gross hack.  Fix it, dammit */
  536.         restart_at:
  537.            pcendptr = expmatch(cp, l_pc, &pcptr, (char *) NULL);
  538.  
  539.            if (pcptr == NULL || atptr < pcptr) {
  540.           putVcp(cp, atptr-1);
  541.           printf("\\LGinlinetrue\\LGbegin\\lgrinde");
  542.           cp = atendptr;
  543.           atendptr = expmatch(cp, l_at, &atptr, (char *) NULL);
  544.           if (atptr != NULL && (pcptr == NULL || atptr < pcptr)) {
  545.              strncpy(temp, cp, atptr-cp);
  546.              temp[atptr-cp] = '\0';
  547.              cp = atendptr;
  548.              printf("\\L{\\LB{");
  549.              putScp(temp);
  550.              printf("}}\\endlgrinde\\LGend{}");
  551.              atendptr = expmatch(cp, l_at, &atptr, (char *) NULL);
  552.              if (atptr != NULL)
  553.             goto restart_at;
  554.              else {
  555.             fputs(cp, stdout); continue;
  556.              }
  557.           } else {
  558.              /* multiline */
  559.           }
  560.            } else {
  561.           fputs(buf, stdout);
  562.           continue;
  563.            }
  564.         } else if (do_tt &&
  565.                (ttendptr = expmatch(buf, l_tt, &ttptr,
  566.                         (char *) NULL)) != NULL) {
  567.            pcendptr = expmatch(buf, l_pc, &pcptr, (char *) NULL);
  568.  
  569.            if (pcptr == NULL || ttptr < pcptr) {
  570.           putVcp(buf, ttptr-1);
  571.            } else {
  572.           fputs(buf, stdout); continue;
  573.            }
  574.         } else {
  575.            fputs(buf, stdout);
  576.            continue;
  577.         }
  578.      } /* @if (!code)@ */
  579.      
  580.      /*
  581.       * We're in embedded code.
  582.       */
  583.      if (buf[0] == '%') {
  584.         if (buf[1] == '*') {
  585.            if (term != ']')
  586.           fprintf(stderr, "%%* only makes sense in display mode\n");
  587.            else {
  588.           printf("\\endlgrinde\\LGend\n");
  589.           printf("\\LGinlinefalse\\LGbegin\\lgrinde\n");
  590.            }
  591.            continue;
  592.         } else if (buf[1] == term) {
  593.            if (buf[2] == '\n')
  594.           printf("\\endlgrinde\\LGend\n");
  595.            else
  596.           printf("\\endlgrinde%s", &buf[2]);
  597.            code = FALSE;
  598.            continue;
  599.         } else if (buf[1] == '=') {    /* Send literal    */
  600.            fputs(&buf[2], stdout);
  601.            continue;
  602.         } else if (buf[1] == '[' || buf[1] == '('
  603.                || buf[1] == ']' || buf[1] == ')') {
  604.            fprintf(stderr,
  605.                "Possible nested embedded code at line %d in %s\n",
  606.                lineno, fname);
  607.         }
  608.      }
  609.      
  610.      /*
  611.       * Inline code --- suppress leading whitespace
  612.       */
  613.      if (inline) {
  614.         while (isspace(*cp))
  615.            cp++;
  616.      }
  617.       } /* @if (embed)@ */
  618.       
  619.       if (*cp == '\f') {
  620.      printf("\\NewPage\n");
  621.      cp++;
  622.      if (*cp == '\n')  /* some people like ^Ls on their own line */
  623.         continue;
  624.       }
  625.       prccont = FALSE;
  626.       printf("\\L{\\LB{");
  627.       putScp(cp);
  628.       if (!embed && prccont && (psptr >= 0)) {
  629.      printf("\\ProcCont{");
  630.      putstr(pstack[psptr]);
  631.      printf("}");
  632.       }
  633. #ifdef DEBUG
  634.       printf("com %o str %o chr %o ptr %d\n", incomm, instr, inchr, psptr);
  635. #endif
  636.    } /* @while fgets()@ */
  637. }
  638.  
  639.  
  640.  
  641. /*
  642.  * Set all of the language-dependent variables
  643.  */
  644.    void
  645. setlang()
  646. {
  647.    char    *p, *cp;
  648.    int i;
  649.  
  650.    /*
  651.     *  get the language definition from the defs file
  652.     */
  653.    i = tgetent(defs, language, defsfile);
  654.    if (i == 0) {
  655.       fprintf(stderr, "no entry for language %s\n", language);
  656.       exit(BADEXIT);
  657.    } else if (i < 0) {
  658.       fprintf(stderr,  "cannot find lgrindefs file `%s'\n", defsfile);
  659.       exit(BADEXIT);
  660.    }
  661.  
  662.    p = strings;
  663.    if (tgetstr("kw", &p) == NULL)
  664.       nokeyw = TRUE;
  665.    else  {
  666.       char **cpp;
  667.       
  668.       cpp = l_keywds;
  669.       cp = strings;
  670.       while (*cp) {
  671.      while (*cp == ' ' || *cp =='\t')
  672.         *cp++ = '\0';
  673.      if (*cp)
  674.         *cpp++ = cp;
  675.      while (*cp != ' ' && *cp  != '\t' && *cp)
  676.         cp++;
  677.       }
  678.       *cpp = NULL;
  679.    }
  680.    
  681.    p = buf;  l_prcbeg = convexp(tgetstr("pb", &p));
  682.    p = buf;  l_combeg = convexp(tgetstr("cb", &p));
  683.    p = buf;  l_comend = convexp(tgetstr("ce", &p));
  684.    p = buf;  l_acmbeg = convexp(tgetstr("ab", &p));
  685.    p = buf;  l_acmend = convexp(tgetstr("ae", &p));
  686.    p = buf;  l_strbeg = convexp(tgetstr("sb", &p));
  687.    p = buf;  l_strend = convexp(tgetstr("se", &p));
  688.    p = buf;  l_blkbeg = convexp(tgetstr("bb", &p));
  689.    p = buf;  l_blkend = convexp(tgetstr("be", &p));
  690.    p = buf;  l_chrbeg = convexp(tgetstr("lb", &p));
  691.    p = buf;  l_chrend = convexp(tgetstr("le", &p));
  692.    p = s_cdebeg;  l_cdebeg = convexp(tgetstr("zb", &p));
  693.    p = buf;  l_cdeend = convexp(tgetstr("ze", &p));
  694.    p = buf;  l_texbeg = convexp(tgetstr("tb", &p));
  695.    p = buf;  l_texend = convexp(tgetstr("te", &p));
  696.    p = buf;  l_txmbeg = convexp(tgetstr("mb", &p));
  697.    p = buf;  l_txmend = convexp(tgetstr("me", &p));
  698.    p = buf;  l_tt_beg = convexp(tgetstr("vb", &p));
  699.    p = buf;  l_tt_end = convexp(tgetstr("ve", &p));
  700.  
  701.    l_tt = convexp("\\|");
  702.    l_at = convexp("@");
  703.    l_pc = convexp("%");
  704.    
  705.    l_escape = '\\';
  706.    l_onecase = tgetflag("oc");
  707.    
  708.    re_strncmp = l_onecase ? lc_strncmp : strncmp;
  709.    l_toplex = tgetflag("tl");
  710. }
  711.  
  712.  
  713.  
  714. /*
  715.  * Write out a formatted line of program text
  716.  */
  717.    void
  718. putScp(os)
  719.    char    *os;
  720. {
  721.    register char *s = os; /* pointer to unmatched string */
  722.    register char *s1;    /* temp. string */
  723.    char *comptr;    /* start of a comment delimiter */
  724.    char *comendptr;    /* end of a comment delimiter */
  725.    char *acmptr;    /* start of an alt. comment delimiter */
  726.    char *acmendptr;    /* end of an alt. comment delimiter */
  727.    char *strptr;    /* start of a string delimiter */
  728.    char *strendptr;    /* end of a string delimiter */
  729.    char *chrptr;    /* start of a char. const delimiter */
  730.    char *chrendptr;    /* end of a char. const delimiter */
  731.    char *cdeptr;    /* start of prog text delim within a comment */
  732.    char *cdeendptr;    /* end of prog text delim within a comment */
  733.    char *cdbptr;    /* start of prog text delim within a comment */
  734.    char *cdbendptr;    /* end of prog text delim within a comment */
  735.    char *texptr;    /* start of %%\TeX%% text delim within a comment */
  736.    char *texendptr;    /* end of %%\TeX%% text delim within a comment */
  737.    char *txmptr;    /* start of %%\TeX%% math delim within a comment */
  738.    char *txmendptr;    /* end of %%\TeX%% math delim within a comment */
  739.    char *tt_ptr;    /* start of typewriter delim within a comment */
  740.    char *tt_endptr;    /* end of typewriter delim within a comment */
  741.    char *blksptr;    /* start of a lexical block start */
  742.    char *blksendptr;    /* end of a lexical block start */
  743.    char *blkeptr;    /* start of a lexical block end */
  744.    char *blkeendptr;    /* end of a lexical block end */
  745.    
  746.    _start = os;        /* remember the start for @expmatch()@ */
  747.    _escaped = FALSE;
  748.    if (nokeyw || incomm || instr)
  749.       goto skip;
  750.    if (isproc(s)) {
  751.       printf("\\Proc{");
  752.       putstr(pname);
  753.       printf("}");
  754.       if (!embed && psptr < PSMAX-1) {
  755.      ++psptr;
  756.      strncpy(pstack[psptr], pname, PNAMELEN);
  757.      pstack[psptr][PNAMELEN] = '\0';
  758.      plstack[psptr] = blklevel;
  759.       }
  760.    } 
  761.  skip:
  762.    do {
  763.       /* check for string, comment, blockstart, etc */
  764.       if (!incomm && !instr && !inchr) {
  765.      
  766.      blkeendptr = expmatch(s, l_blkend, &blkeptr, (char *) NULL);
  767.      blksendptr = expmatch(s, l_blkbeg, &blksptr, (char *) NULL);
  768.      comendptr =  expmatch(s, l_combeg, &comptr,  (char *) NULL);
  769.      acmendptr =  expmatch(s, l_acmbeg, &acmptr,  (char *) NULL);
  770.      strendptr =  expmatch(s, l_strbeg, &strptr,  (char *) NULL);
  771.      chrendptr =  expmatch(s, l_chrbeg, &chrptr,  (char *) NULL);
  772.      
  773.      /* check for end of program text in comment */
  774.      if (incode != NOTCODE) {
  775.         cdeendptr = expmatch(s, l_cdeend, &cdeptr, (char *) NULL);
  776.  
  777.         if ((cdeptr == NULL && (comptr != NULL || acmptr != NULL))
  778.         || (cdeptr != NULL
  779.             && ((comptr != NULL && comptr < cdeptr)
  780.             || ((acmptr != NULL && acmptr < cdeptr))))) {
  781.            fprintf(stderr,
  782. "Comments may not be nested within program text within comments\n");
  783.            s = (comptr != NULL) ? comptr : acmptr;
  784.            incode = NOTCODE;
  785.            continue;
  786.         }
  787.  
  788.         /* look to see if there's a \<zb> in the program text */
  789.         cdbendptr = expmatch(s, l_cdebeg, &cdbptr, (char *) NULL);
  790.         if (cdeptr != NULL
  791.         && (strptr  == NULL || cdbptr < strptr)
  792.         && (chrptr  == NULL || cdbptr < chrptr)
  793.         && (blksptr == NULL || cdbptr < blksptr)
  794.         && (blkeptr == NULL || cdbptr < blkeptr)) {
  795.            if (cdbptr > s && cdbptr[-1] == l_escape) {
  796.           putKcp(s, cdbptr-2, FALSE);
  797.           printf("\\C{}");
  798.           putKcp(s_cdebeg, s_cdebeg + strlen(s_cdebeg) - 1, TRUE);
  799.           printf("\\CE{}");
  800.           s = cdbendptr; 
  801.           incode = OTHERCODE;
  802.           continue;
  803.            }
  804.         }
  805.  
  806.         comendptr =
  807.            expmatch(s, (comtype == STANDARD) ? l_comend : l_acmend,
  808.             &comptr, (char *) NULL);
  809.  
  810.         if ((cdeptr == NULL && comptr != NULL)
  811.         || (cdeptr != NULL && (comptr != NULL && comptr < cdeptr))) {
  812.            fprintf(stderr,
  813.                "Unterminated program text within comment\n");
  814.            printf("\\C{}");
  815.            s = comptr;
  816.            incode = NOTCODE; incomm = TRUE;
  817.            continue;
  818.         }
  819.         
  820.         
  821.         if (cdeendptr != NULL) {
  822.            if ((strptr  == NULL || cdeptr < strptr)
  823.            && (chrptr  == NULL || cdeptr < chrptr)
  824.            && (blksptr == NULL || cdeptr < blksptr)
  825.            && (blkeptr == NULL || cdeptr < blkeptr)) {
  826.           if (incode == INITCODE && cdeptr == s) {
  827.              printf("\\C{}");
  828.              putKcp(s_cdebeg, s_cdebeg + strlen(s_cdebeg) - 1, TRUE);
  829.           } else {
  830.              putKcp(s, cdeptr-1, FALSE);
  831.              printf("\\C{}");
  832.           }
  833.           s = cdeendptr;
  834.           incode = NOTCODE; incomm = TRUE;
  835.           continue;
  836.            }
  837.         } else if (strptr == NULL && chrptr == NULL
  838.                && blksptr == NULL && blkeptr == NULL) {
  839.            cdeptr = s;
  840.            s += strlen(s);
  841.            putKcp(cdeptr, s-1, FALSE);
  842.            incode = OTHERCODE;
  843.            continue;
  844.         } /* else there is a string/char/block on this line */
  845.  
  846.         incode = OTHERCODE;
  847.      } /* @if (incode)@ */
  848.  
  849.  
  850.      /* start of a comment? */
  851.      if (comptr != NULL
  852.          && (strptr  == NULL || comptr < strptr)
  853.          && (acmptr  == NULL || comptr < acmptr)
  854.          && (chrptr  == NULL || comptr < chrptr)
  855.          && (blksptr == NULL || comptr < blksptr)
  856.          && (blkeptr == NULL || comptr < blkeptr)) {
  857.         putKcp(s, comptr-1, FALSE);
  858.         printf("\\C{}");
  859.         s = comendptr;
  860.         putKcp(comptr, comendptr-1, FALSE);
  861.         incomm = TRUE;
  862.         comtype = STANDARD;
  863.         continue;
  864.      }
  865.      
  866.      /* start of an alternate-form comment? */
  867.      if (acmptr != NULL
  868.          && (strptr  == NULL || acmptr < strptr)
  869.          && (chrptr  == NULL || acmptr < chrptr)
  870.          && (blksptr == NULL || acmptr < blksptr)
  871.          && (blkeptr == NULL || acmptr < blkeptr)) {
  872.         putKcp(s, acmptr-1, FALSE);
  873.         printf("\\C{}");
  874.         s = acmendptr;
  875.         putKcp(acmptr, acmendptr, FALSE);
  876.         incomm = TRUE;
  877.         comtype = ALTERNATE;
  878.         continue;
  879.      }
  880.      
  881.      /* start of a string? */
  882.      if (strptr != NULL
  883.          && (chrptr  == NULL || strptr < chrptr)
  884.          && (blksptr == NULL || strptr < blksptr)
  885.          && (blkeptr == NULL || strptr < blkeptr)) {
  886.         putKcp(s, strptr-1, FALSE);
  887.         printf("\\S{}");
  888.         s = strendptr;
  889.         putKcp(strptr, strendptr-1, FALSE);
  890.         instr = TRUE;
  891.         continue;
  892.      }
  893.      
  894.      /* start of a character string? */
  895.      if (chrptr != NULL
  896.          && (blksptr == NULL || chrptr < blksptr)
  897.          && (blkeptr == NULL || chrptr < blkeptr)) {
  898.         putKcp(s, chrptr-1, FALSE);
  899.         printf("\\S{}");
  900.         s = chrendptr;
  901.         putKcp(chrptr, chrendptr-1, FALSE);
  902.         inchr = TRUE;
  903.         continue;
  904.      }
  905.      
  906.      /* end of a lexical block */
  907.      if (blkeptr != NULL) {
  908.         if (blksptr == NULL || blkeptr < blksptr) {
  909.            putKcp(s, blkeendptr - 1, FALSE);
  910.            s = blkeendptr;
  911.            blklevel--;
  912.            if (psptr >= 0 && plstack[psptr] >= blklevel) {
  913.           
  914.           /* end of current procedure */
  915.           blklevel = plstack[psptr];
  916.           
  917.           /* see if we should print the last proc name */
  918.           if (--psptr >= 0)
  919.              prccont = TRUE;
  920.           else
  921.              psptr = -1;
  922.            }
  923.            continue;
  924.         }
  925.      }
  926.      
  927.      /* start of a lexical block */
  928.      if (blksptr != NULL) {
  929.         putKcp(s, blksendptr - 1, FALSE);
  930.         s = blksendptr;
  931.         blklevel++;
  932.         continue;
  933.      }
  934.      
  935.      /* check for end of comment */
  936.       } else if (incomm) {
  937.  
  938.      cdeendptr = expmatch(s, l_cdebeg, &cdeptr, (char *) NULL);
  939.      texendptr = expmatch(s, l_texbeg, &texptr, (char *) NULL);
  940.      txmendptr = expmatch(s, l_txmbeg, &txmptr, (char *) NULL);
  941.      tt_endptr = expmatch(s, l_tt_beg, &tt_ptr, (char *) NULL);
  942.  
  943.      if (code_cmnts) {
  944.  
  945.         /* Check for program text within comment */
  946.         if (cdeptr != NULL
  947.         && (texptr == NULL || cdeptr < texptr)
  948.         && (tt_ptr == NULL || cdeptr < tt_ptr)
  949.         && (txmptr == NULL || cdeptr < txmptr)) {
  950.            putKcp(s, cdeptr-1, TRUE);
  951.            printf("\\CE{}");
  952.            s = cdeendptr;
  953.            incode = INITCODE; incomm = FALSE;
  954.            continue;
  955.         }
  956.         
  957.         /* Check for %%\TeX%% text within comment */
  958.         if (texptr != NULL
  959.         && (tt_ptr == NULL || texptr < tt_ptr)
  960.         && (txmptr == NULL || texptr < txmptr)) {
  961.            putKcp(s, texptr-1, TRUE);
  962.            s = texendptr;
  963.            if ((texendptr =
  964.             expmatch(s, l_texend, &texptr, (char *) NULL)) != NULL) {
  965.           putchar('{'); putVcp(s, texptr-1); putchar('}');
  966.           s = texendptr;
  967.            } else {
  968.           fprintf(stderr,
  969.       "TeX text within a comment must all be on one line\n");
  970.           s += strlen(s);
  971.            }
  972.            continue;
  973.         }
  974.         
  975.         /* Check for typewriter text within comment */
  976.         if (tt_ptr != NULL
  977.         && (txmptr == NULL || tt_ptr < txmptr)) {
  978.            putKcp(s, tt_ptr-1, TRUE);
  979.            s = tt_endptr;
  980.            if ((tt_endptr =
  981.             expmatch(s, l_tt_end, &tt_ptr, (char *) NULL)) != NULL) {
  982.           printf("{\\tt ");
  983.           putKcp(s, tt_ptr-1, TRUE);
  984.           printf("}");
  985.           s = tt_endptr;
  986.            } else {
  987.           fprintf(stderr,
  988.       "typewriter text within a comment must all be on one line\n\t%s", s);
  989.           s += strlen(s);
  990.            }
  991.            continue;
  992.         }
  993.         
  994.         /* Check for %%\TeX%% math within comment */
  995.         if (txmptr != NULL) {
  996.            putKcp(s, txmptr-1, TRUE);
  997.            s = txmendptr;
  998.            if ((txmendptr =
  999.             expmatch(s, l_txmend, &txmptr, (char *) NULL)) != NULL) {
  1000.           putchar('$'); putVcp(s, txmptr-1); putchar('$');
  1001.           s = txmendptr;
  1002.            } else {
  1003.           fprintf(stderr,
  1004.       "TeX math within a comment must all be on one line\n");
  1005.           s += strlen(s);
  1006.            }
  1007.            continue;
  1008.         }
  1009.      } /* @if (code_cmnts)@ */
  1010.  
  1011.      if ((comendptr =
  1012.             expmatch(s, (comtype == STANDARD) ? l_comend : l_acmend,
  1013.              (char **) NULL, (char *) NULL)) != NULL) {
  1014.         putKcp(s, comendptr-1, TRUE);
  1015.         s = comendptr;
  1016.         incomm = FALSE;
  1017.         printf("\\CE{}");
  1018.      } else {
  1019.         comptr = s;
  1020.         s += strlen(s);
  1021.         putKcp(comptr, s-1, TRUE);
  1022.      }
  1023.      continue;
  1024.      
  1025.      /* check for end of string */
  1026.       } else if (instr) {
  1027.      if ((strendptr =
  1028.           expmatch(s, l_strend, (char **) NULL, (char *) NULL)) != NULL) {
  1029.         putKcp(s, strendptr-1, TRUE);
  1030.         s = strendptr;
  1031.         instr = FALSE;
  1032.         printf("\\SE{}");
  1033.      } else {
  1034.         strptr = s;
  1035.         s += strlen(s);
  1036.         putKcp(strptr, s-1, TRUE);
  1037.      }
  1038.      continue;
  1039.      
  1040.      /* check for end of character string */
  1041.       } else if (inchr) {
  1042.      if ((chrendptr =
  1043.           expmatch(s, l_chrend, (char **) NULL, (char *) NULL)) != NULL) {
  1044.         putKcp(s, chrendptr-1, TRUE);
  1045.         s = chrendptr;
  1046.         inchr = FALSE;
  1047.         printf("\\SE{}");
  1048.      } else {
  1049.         chrptr = s;
  1050.         s += strlen(s);
  1051.         putKcp(chrptr, s-1, TRUE);
  1052.      }
  1053.      continue;
  1054.       }
  1055.       
  1056.       /* print out the line */
  1057.       chrptr = s;
  1058.       s += strlen(s);
  1059.       putKcp(chrptr, s-1, FALSE);
  1060.       
  1061.    } while (*s);
  1062. }
  1063.  
  1064.  
  1065.  
  1066. /*
  1067.  * Output a %%\LaTeX%% command to tab to column "col" (see lgrind.doc
  1068.  * for a partial explanation of the bizarre brace arrangement).
  1069.  */
  1070. #define tabto(col) printf("}\\Tab{%d}{", col);
  1071.       
  1072.  
  1073.  
  1074. /*
  1075.  * @islidchr()@ is @TRUE@ for things that can begin identifiers;
  1076.  * @isidchr@ is @TRUE@ of identifier constituents.
  1077.  */
  1078. #define islidchr(c)(isalpha(c) || (c) == '_' || (c) == '$')
  1079. #define isidchr(c) (isalnum(c) || (c) == '_' || (c) == '$')
  1080.  
  1081.  
  1082.  
  1083. /*
  1084.  * Write out a portion of the line
  1085.  */
  1086.    void
  1087. putKcp(start, end, nix)
  1088.    char        *start;        /* Start of string to write        */
  1089.    char        *end;        /* End of string to write        */
  1090.    boolean    nix;        /* Don't look for identifiers, numbers    */
  1091. {
  1092.    int i, c;
  1093.    
  1094.    while (start <= end) {
  1095.       c = *start++;
  1096.       /*
  1097.        * take care of nice tab stops
  1098.        */
  1099.       if (c == '\t') {
  1100.      while (start <= end && *start == '\t')
  1101.         start++;
  1102.      tabto(width(_start, start));
  1103.      continue;
  1104.       }
  1105.       
  1106.       /*
  1107.        * First split off numbers.  We have a rather ad hoc
  1108.        * definition:  A number is a digit followed by any number
  1109.        * of digits or letters, and periods.
  1110.        * This produces meaningless parses --- %$.2$% is parsed as %|.|%
  1111.        * followed by the number %|2|% --- but should produce decent
  1112.        * results for most languages (outside of maybe FORTRAN and DCL).
  1113.        */
  1114.       if (!nix) {
  1115.      if (isdigit(c)) {
  1116.         do {
  1117.            if (c == 'l')
  1118.           printf("$\\ell$");
  1119.            else
  1120.           outchar(c);
  1121.            c = *start++;
  1122.         } while (isalnum(c) || c == '.');
  1123.         start--;
  1124.         continue;
  1125.      } else if (c == '#' || islidchr(c)) {
  1126.         i = getid(--start);
  1127.         if (i > 0)
  1128.            printf("\\K{");
  1129.         else {
  1130.            printf("\\V{");
  1131.            i = -i;
  1132.         }
  1133.         while (--i >= 0) {
  1134.            c = *start++;
  1135.            outchar(c);
  1136.         }
  1137.         putchar('}');
  1138.         continue;
  1139.      }
  1140.       }
  1141.       outchar(c);
  1142.    }
  1143. }
  1144.  
  1145.  
  1146.  
  1147. /*
  1148.  * Write out a portion of the line verbatim
  1149.  */
  1150.    void
  1151. putVcp(start, end)
  1152.    char        *start;        /* Start of string to write    */
  1153.    char        *end;        /* End of string to write    */
  1154. {
  1155.    for ( ; start <= end; start++) {
  1156.       putchar(*start);
  1157.    }
  1158. }
  1159.  
  1160.  
  1161.  
  1162. /*
  1163.  * Calculate the width of a string, including tabs
  1164.  */
  1165.    int
  1166. width(s, os)
  1167.    register char *s, *os;
  1168. {
  1169.    register int i = 0, c;
  1170.    
  1171.    while (s < os) {
  1172.       c = *s++;
  1173.       if (c == '\t') {
  1174.      i = (i + 8) &~ 7;
  1175.      continue;
  1176.       }
  1177.       if (c < ' ')
  1178.      i += 2;
  1179.       else
  1180.      i++;
  1181.    }
  1182.    return i;
  1183. }
  1184.  
  1185.  
  1186.  
  1187. /*
  1188.  * Output a string, escaping special characters
  1189.  */
  1190.    void
  1191. putstr(cp)
  1192.    register char *cp;
  1193. {
  1194.    register int c;
  1195.     
  1196.    if (cp == NULL)
  1197.       return;
  1198.    while ((c = *cp++) != '\0')
  1199.       outchar(c);
  1200. }
  1201.  
  1202.  
  1203.  
  1204. /*
  1205.  * The following table converts ASCII characters to a printed
  1206.  * representation, taking care of all the %%\LaTeX%% quoting.  N.B.: all
  1207.  * single-character strings are assumed to be equivalent to the
  1208.  * character for that index (i.e., @printtab['c']@ can't be @"f"@).
  1209.  * (This is purely for efficiency hacking.)
  1210.  *
  1211.  * Notes:
  1212.  *  Some pairs of characters are handled specially within @outchar()@;
  1213.  *  this table contains no indication when that happens.
  1214.  *  %|`|% is output as %|{`}|% to avoid various ligatures, such as %|!`|%.
  1215.  *  The %|''|% and %|--|% (and %|---|%) ligatures are not a problem
  1216.  *  because those characters are output as macros anyway.  Using %|{`}|%
  1217.  *  is sufficient since nothing we put out will ever be given to the
  1218.  *  hyphenation algorithms anyway.
  1219.  */
  1220.  
  1221. char *printtab[256] = {
  1222.    "\0x",   "\\^A",  "\\^B",  "\\^C",  "\\^D",  "\\^E",  "\\^F",  "\\^G",
  1223. #ifndef MPW
  1224.    "\\^H",  "\t",    "}}\n",  "\\^K",  "\0x",   "\\^M",  "\\^N",  "\\^O",
  1225. #else
  1226.    "\\^H",  "\t",    "}}\n",  "\\^K",  "\0x",   "}}\n",  "\\^N",  "\\^O",
  1227. #endif
  1228.    "\\^P",  "\\^Q",  "\\^R",  "\\^S",  "\\^T",  "\\^U",  "\\^V",  "\\^W",
  1229.    "\\^X",  "\\^Y",  "\\^Z",  "\\^[",  "\\^\\!","\\^]",  "\\^\\^","\\^\\_",
  1230.    " ",     "!",     "\\\"",  "\\#",   "\\$",   "\\%",   "\\&",   "\\'",
  1231.    "(",     ")",     "\\*",   "+",     ",",     "\\-",   ".",     "\\1",
  1232.    "0",     "1",     "2",     "3",     "4",     "5",     "6",     "7",
  1233.    "8",     "9",     ":",     ";",     "\\<",   "=",     "\\>",   "?",
  1234.    "@",     "A",     "B",     "C",     "D",     "E",     "F",     "G",
  1235.    "H",     "I",     "J",     "K",     "L",     "M",     "N",     "O",
  1236.    "P",     "Q",     "R",     "S",     "T",     "U",     "V",     "W",
  1237.    "X",     "Y",     "Z",     "[",    "\\2",     "]",  "\\^",   "\\_",
  1238.    "{`}",   "a",     "b",     "c",     "d",     "e",     "f",     "g",
  1239.    "h",     "i",     "j",     "k",     "l",     "m",     "n",     "o",
  1240.    "p",     "q",     "r",     "s",     "t",     "u",     "v",     "w",
  1241.    "x",     "y",     "z",     "\\{",   "\\|",   "\\}",   "\\~",   "\\^?",
  1242.    "\200",  "\201",  "\202",  "\203",  "\204",  "\205",  "\206",  "\207",
  1243.    "\210",  "\211",  "\212",  "\213",  "\214",  "\215",  "\216",  "\217",
  1244.    "\220",  "\221",  "\222",  "\223",  "\224",  "\225",  "\226",  "\227",
  1245.    "\230",  "\231",  "\232",  "\233",  "\234",  "\235",  "\236",  "\237",
  1246.    "\240",  "\241",  "\242",  "\243",  "\244",  "\245",  "\246",  "\247",
  1247.    "\250",  "\251",  "\252",  "\253",  "\254",  "\255",  "\256",  "\257",
  1248.    "\260",  "\261",  "\262",  "\263",  "\264",  "\265",  "\266",  "\267",
  1249.    "\270",  "\271",  "\272",  "\273",  "\274",  "\275",  "\276",  "\277",
  1250.    "\300",  "\301",  "\302",  "\303",  "\304",  "\305",  "\306",  "\307",
  1251.    "\310",  "\311",  "\312",  "\313",  "\314",  "\315",  "\316",  "\317",
  1252.    "\320",  "\321",  "\322",  "\323",  "\324",  "\325",  "\326",  "\327",
  1253.    "\330",  "\331",  "\332",  "\333",  "\334",  "\335",  "\336",  "\337",
  1254.    "\340",  "\341",  "\342",  "\343",  "\344",  "\345",  "\346",  "\347",
  1255.    "\350",  "\351",  "\352",  "\353",  "\354",  "\355",  "\356",  "\357",
  1256.    "\360",  "\361",  "\362",  "\363",  "\364",  "\365",  "\366",  "\367",
  1257.    "\370",  "\371",  "\372",  "\373",  "\374",  "\375",  "\376",  "\377",
  1258. };
  1259.  
  1260.  
  1261.  
  1262. #define EMDASH (-1)
  1263. /*
  1264.  * Output one character, fixed up as required.  Since there is no call-back
  1265.  * to tell @outchar()@ to flush what it has stored, it must always produce
  1266.  * some output --- it can't simply retain state.  This makes certain
  1267.  * translations impossible, but we can live without them for now....
  1268.  */ 
  1269.    void
  1270. outchar(c)
  1271.    int    c;
  1272. {
  1273.    if ((linehead || !incomm) && c == ' ') {
  1274.       putchar('_');
  1275.       goto fin;
  1276.    }
  1277.    linehead = FALSE;
  1278.    switch (lastout) {
  1279.    case '.':
  1280.    case '|':
  1281.       if (c == lastout)
  1282.      printf("\\,");
  1283.       break;
  1284.    case ' ':
  1285. #if 0    /* gvr hates this trick */
  1286.       if (incomm && c == '-') {
  1287.      printf("---");
  1288.      c = EMDASH;    /* For future cleverness...    */
  1289.      goto fin;
  1290.       }
  1291. #endif
  1292.       break;
  1293.    case '[':
  1294.       if (c == ']')
  1295.      printf("\\,");
  1296.       break;
  1297.    case '-':
  1298.       if (c == '>')
  1299.      printf("\\!");
  1300.       break;
  1301.    case '<':
  1302.       if (c == '-')
  1303.      printf("\\!");
  1304.       break;
  1305.    }
  1306.    if (incomm && c == '-') {
  1307.       putchar('-');
  1308.       goto fin;
  1309.    }
  1310.    printtab[c][1] ? printf("%s", printtab[c]) : putchar(c);
  1311.  fin:
  1312.    lastout = c;
  1313. }
  1314.  
  1315.  
  1316.  
  1317. /*
  1318.  *    Look for a procedure beginning on this line
  1319.  */
  1320.    boolean
  1321. isproc(s)
  1322.    char    *s;
  1323. {
  1324.    pname[0] = '\0';
  1325.    if ((!l_toplex || blklevel == 0)
  1326.        && expmatch(s, l_prcbeg, (char **) NULL, pname) != NULL)
  1327.       return TRUE;
  1328.    return FALSE;
  1329. }
  1330.  
  1331.  
  1332.  
  1333. /*
  1334.  * Get the identifier starting at @s@.  It is assumed that @s@ may indeed
  1335.  * start an identifier.  Value is %$>0$% for a keyword --- the count of
  1336.  * characters in the keyword --- and %$<0$% if not a keyword, in which
  1337.  * case the value returned is the negative of the number of bytes in
  1338.  * the matched identifier.
  1339.  *
  1340.  * This function checks @nokeyw@ and won't check to see if the
  1341.  * identifier found is a keyword if it is @TRUE@.
  1342.  */
  1343.    int
  1344. getid(s)
  1345.    char    *s;
  1346. {
  1347.    char    **ss    = l_keywds;
  1348.    int    i    = 1;
  1349.    char    *cp    = s;
  1350.    int    firstc    = *s;
  1351.    
  1352.    while (++cp, isidchr(*cp))
  1353.       i++;
  1354.    if (nokeyw)
  1355.       return -i;
  1356.    while (cp = *ss++) {
  1357.       if (!l_onecase && firstc != *cp)
  1358.      continue;
  1359.       if ((*re_strncmp)(s, cp, i) == 0 && !isidchr(cp[i]))
  1360.      return i;
  1361.    }
  1362.    return -i;
  1363. }
  1364.  
  1365.  
  1366.  
  1367. /*
  1368.  * @getredirection()@ is intended to aid in porting C programs
  1369.  * to VMS (Vax-11 C) which does not support %|>|% and %|<|%
  1370.  * I/O redirection.  With suitable modification, it may
  1371.  * useful for other portability problems as well.
  1372.  *
  1373.  * Modified, 24-Jan-86 by Jerry Leichter
  1374.  *    When creating a new output file, force the maximum record size to
  1375.  *    512; otherwise, it ends up as 0 (though the C I/O system won't write
  1376.  *    a record longer than 512 bytes anyway) which will cause problems if
  1377.  *    the file is later opened for @APPEND@ --- if the maximum record size
  1378.  *    is 0, C will use the length of the longest record written to the file
  1379.  *    for its buffer!
  1380.  */
  1381.  
  1382. #ifdef    vms
  1383. #  include    <stdio.h>
  1384. #  include    <errno.h>
  1385.  
  1386.    int
  1387. getredirection(argc, argv)
  1388.    int    argc;
  1389.    char    **argv;
  1390. /*
  1391.  * Process VMS redirection args.  Exit if any error is seen.
  1392.  * If @getredirection()@ processes an argument, it is erased
  1393.  * from the vector.  @getredirection()@ returns a new @argc@ value.
  1394.  *
  1395.  * Warning: do not try to simplify the code for VMS.  The code
  1396.  * presupposes that @getredirection()@ is called before any data is
  1397.  * read from @stdin@ or written to @stdout@.
  1398.  *
  1399.  * Normal usage is as follows:
  1400.  *@
  1401.  *    main(argc, argv)
  1402.  *    int        argc;
  1403.  *    char        *argv[];
  1404.  *    {
  1405.  *        argc = getredirection(argc, argv);
  1406.  *    }@
  1407.  */
  1408. {
  1409.    register char    *ap;    /* Argument pointer */
  1410.    int            i;    /* @argv[]@ index */
  1411.    int            j;    /* Output index */
  1412.    int            file;    /* File_descriptor */
  1413.    
  1414.    for (j = i = 1; i < argc; i++) {   /* Do all arguments */
  1415.       switch (*(ap = argv[i])) {
  1416.       case '<':            /* %|<file|% */
  1417.      if (freopen(++ap, "r", stdin) == NULL) {
  1418.         perror(ap);        /* Can't find file */
  1419.         exit(errno);    /* Is a fatal error */
  1420.      }
  1421.      break;
  1422.      
  1423.       case '>':            /* %|>file|% or %|>>file|% */
  1424.      if (*++ap == '>') {    /* %|>>file|% */
  1425.         /*
  1426.          * If the file exists, and is writable by us,
  1427.          * call @freopen()@ to append to the file (using the
  1428.          * file's current attributes).  Otherwise, create
  1429.          * a new file with "vanilla" attributes as if
  1430.          * the argument was given as %|>filename|%.
  1431.          * @access(name, 2)@ is @TRUE@ if we can write on
  1432.          * the specified file.
  1433.          */
  1434.         if (access(++ap, 2) == 0) {
  1435.            if (freopen(ap, "a", stdout) != NULL)
  1436.           break;    /* Exit @case@ statement */
  1437.            perror(ap);    /* Error, can't append */
  1438.            exit(errno);    /* After @access@ test */
  1439.         }            /* If file accessable */
  1440.      }
  1441.      /*
  1442.       * On VMS, we want to create the file using "standard"
  1443.       * record attributes.  @create(...)@ creates the file
  1444.       * using the caller's default protection mask and
  1445.       * "variable length, implied carriage return"
  1446.       * attributes.  @dup2()@ associates the file with @stdout@.
  1447.       */
  1448.      if ((file = creat(ap, 0, "rat=cr", "rfm=var", "mrs=512")) == -1
  1449.          || dup2(file, fileno(stdout)) == -1) {
  1450.         perror(ap);        /* Can't create file    */
  1451.         exit(errno);    /* is a fatal error    */
  1452.      }            /* If %|>|% creation    */
  1453.      break;            /* Exit @case@ test    */
  1454.      
  1455.       default:
  1456.      argv[j++] = ap;    /* Not a redirector    */
  1457.      break;            /* Exit @case@ test    */
  1458.       }
  1459.    }                /* For all arguments    */
  1460.    argv[j] = NULL;        /* Terminate @argv[]@    */
  1461.    return j;            /* Return new @argc@    */
  1462. }
  1463.  
  1464. #else    /* @!vms@ */
  1465.  
  1466. getredirection(argc, argv)
  1467.    int        argc;
  1468.    char        *argv[];
  1469.    /*
  1470.     * Dummy routine.
  1471.     */
  1472. {
  1473.    return (argv[0], argc);
  1474. }
  1475.  
  1476. #endif    /* @!vms@ */
  1477.